home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / ncurses-5.3.lha / ncurses-5.3 / test / view.c < prev    next >
C/C++ Source or Header  |  2002-10-24  |  11KB  |  513 lines

  1. /*
  2.  * view.c -- a silly little viewer program
  3.  *
  4.  * written by Eric S. Raymond <esr@snark.thyrsus.com> December 1994
  5.  * to test the scrolling code in ncurses.
  6.  *
  7.  * modified by Thomas Dickey <dickey@clark.net> July 1995 to demonstrate
  8.  * the use of 'resizeterm()', and May 2000 to illustrate wide-character
  9.  * handling.
  10.  *
  11.  * Takes a filename argument.  It's a simple file-viewer with various
  12.  * scroll-up and scroll-down commands.
  13.  *
  14.  * n    -- scroll one line forward
  15.  * p    -- scroll one line back
  16.  *
  17.  * Either command accepts a numeric prefix interpreted as a repeat count.
  18.  * Thus, typing `5n' should scroll forward 5 lines in the file.
  19.  *
  20.  * The way you can tell this is working OK is that, in the trace file,
  21.  * there should be one scroll operation plus a small number of line
  22.  * updates, as opposed to a whole-page update.  This means the physical
  23.  * scroll operation worked, and the refresh() code only had to do a
  24.  * partial repaint.
  25.  *
  26.  * $Id: view.c,v 1.53 2002/06/29 23:28:27 tom Exp $
  27.  */
  28.  
  29. #include <ctype.h>
  30. #include <time.h>
  31.  
  32. #include <test.priv.h>
  33.  
  34. #if HAVE_TERMIOS_H
  35. # include <termios.h>
  36. #else
  37. # include <sgtty.h>
  38. #endif
  39.  
  40. #if !defined(sun) || !HAVE_TERMIOS_H
  41. # if HAVE_SYS_IOCTL_H
  42. #  include <sys/ioctl.h>
  43. # endif
  44. #endif
  45.  
  46. #define my_pair 1
  47.  
  48. /* This is needed to compile 'struct winsize' */
  49. #if NEED_PTEM_H
  50. #include <sys/stream.h>
  51. #include <sys/ptem.h>
  52. #endif
  53.  
  54. static RETSIGTYPE finish(int sig) GCC_NORETURN;
  55. static void show_all(const char *tag);
  56.  
  57. #if defined(SIGWINCH) && defined(TIOCGWINSZ) && HAVE_RESIZETERM
  58. #define CAN_RESIZE 1
  59. #else
  60. #define CAN_RESIZE 0
  61. #endif
  62.  
  63. #if CAN_RESIZE
  64. static RETSIGTYPE adjust(int sig);
  65. static int interrupted;
  66. #endif
  67.  
  68. static bool waiting = FALSE;
  69. static int shift = 0;
  70. static bool try_color = FALSE;
  71.  
  72. static char *fname;
  73. static NCURSES_CH_T **my_lines;
  74. static NCURSES_CH_T **lptr;
  75.  
  76. static void
  77. usage(void)
  78. {
  79.     static const char *msg[] =
  80.     {
  81.     "Usage: view [options] file"
  82.     ,""
  83.     ,"Options:"
  84.     ," -c       use color if terminal supports it"
  85.     ," -i       ignore INT, QUIT, TERM signals"
  86.     ," -n NUM   specify maximum number of lines (default 1000)"
  87. #if defined(KEY_RESIZE)
  88.     ," -r       use old-style sigwinch handler rather than KEY_RESIZE"
  89. #endif
  90. #ifdef TRACE
  91.     ," -t       trace screen updates"
  92.     ," -T NUM   specify trace mask"
  93. #endif
  94.     };
  95.     size_t n;
  96.     for (n = 0; n < SIZEOF(msg); n++)
  97.     fprintf(stderr, "%s\n", msg[n]);
  98.     ExitProgram(EXIT_FAILURE);
  99. }
  100.  
  101. static int
  102. ch_len(NCURSES_CH_T * src)
  103. {
  104.     int result = 0;
  105. #if USE_WIDEC_SUPPORT
  106. #endif
  107.  
  108. #if USE_WIDEC_SUPPORT
  109.     while (getcchar(src++, NULL, NULL, NULL, NULL) > 0)
  110.     result++;
  111. #else
  112.     while (*src++)
  113.     result++;
  114. #endif
  115.     return result;
  116. }
  117.  
  118. /*
  119.  * Allocate a string into an array of chtype's.  If UTF-8 mode is
  120.  * active, translate the string accordingly.
  121.  */
  122. static NCURSES_CH_T *
  123. ch_dup(char *src)
  124. {
  125.     unsigned len = strlen(src);
  126.     NCURSES_CH_T *dst = typeMalloc(NCURSES_CH_T, len + 1);
  127.     unsigned j, k;
  128. #if USE_WIDEC_SUPPORT
  129.     wchar_t wstr[CCHARW_MAX + 1];
  130.     wchar_t wch;
  131.     int l = 0;
  132.     mbstate_t state;
  133.     size_t rc;
  134.     int width;
  135. #endif
  136.  
  137. #if USE_WIDEC_SUPPORT
  138.     memset(&state, 0, sizeof(state));
  139. #endif
  140.     for (j = k = 0; j < len; j++) {
  141. #if USE_WIDEC_SUPPORT
  142.     rc = mbrtowc(&wch, src + j, len - j, &state);
  143.     if (rc == (size_t) -1 || rc == (size_t) -2)
  144.         break;
  145.     j += rc - 1;
  146.     if ((width = wcwidth(wch)) < 0)
  147.         break;
  148.     if ((width > 0 && l > 0) || l == CCHARW_MAX) {
  149.         wstr[l] = L'\0';
  150.         l = 0;
  151.         if (setcchar(dst + k, wstr, 0, 0, NULL) != OK)
  152.         break;
  153.         ++k;
  154.     }
  155.     if (width == 0 && l == 0)
  156.         wstr[l++] = L' ';
  157.     wstr[l++] = wch;
  158. #else
  159.     dst[k++] = src[j];
  160. #endif
  161.     }
  162. #if USE_WIDEC_SUPPORT
  163.     if (l > 0) {
  164.     wstr[l] = L'\0';
  165.     if (setcchar(dst + k, wstr, 0, 0, NULL) == OK)
  166.         ++k;
  167.     }
  168.     setcchar(dst + k, L"", 0, 0, NULL);
  169. #else
  170.     dst[k] = 0;
  171. #endif
  172.     return dst;
  173. }
  174.  
  175. int
  176. main(int argc, char *argv[])
  177. {
  178.     int MAXLINES = 1000;
  179.     FILE *fp;
  180.     char buf[BUFSIZ];
  181.     int i;
  182.     int my_delay = 0;
  183.     NCURSES_CH_T **olptr;
  184.     int length = 0;
  185.     int value = 0;
  186.     bool done = FALSE;
  187.     bool got_number = FALSE;
  188. #if CAN_RESIZE
  189.     bool nonposix_resize = FALSE;
  190. #endif
  191.     const char *my_label = "Input";
  192.  
  193.     setlocale(LC_ALL, "");
  194.  
  195. #ifndef NCURSES_VERSION
  196.     /*
  197.      * We know ncurses will catch SIGINT if we don't establish our own handler.
  198.      * Other versions of curses may/may not catch it.
  199.      */
  200.     (void) signal(SIGINT, finish);    /* arrange interrupts to terminate */
  201. #endif
  202.  
  203.     while ((i = getopt(argc, argv, "cin:rtT:")) != EOF) {
  204.     switch (i) {
  205.     case 'c':
  206.         try_color = TRUE;
  207.         break;
  208.     case 'i':
  209.         signal(SIGINT, SIG_IGN);
  210.         signal(SIGQUIT, SIG_IGN);
  211.         signal(SIGTERM, SIG_IGN);
  212.         break;
  213.     case 'n':
  214.         if ((MAXLINES = atoi(optarg)) < 1)
  215.         usage();
  216.         break;
  217. #if CAN_RESIZE
  218.     case 'r':
  219.         nonposix_resize = TRUE;
  220.         break;
  221. #endif
  222. #ifdef TRACE
  223.     case 'T':
  224.         trace(atoi(optarg));
  225.         break;
  226.     case 't':
  227.         trace(TRACE_CALLS);
  228.         break;
  229. #endif
  230.     default:
  231.         usage();
  232.     }
  233.     }
  234.     if (optind + 1 != argc)
  235.     usage();
  236.  
  237.     if ((my_lines = typeMalloc(NCURSES_CH_T *, MAXLINES + 2)) == 0)
  238.     usage();
  239.  
  240.     fname = argv[optind];
  241.     if ((fp = fopen(fname, "r")) == 0) {
  242.     perror(fname);
  243.     ExitProgram(EXIT_FAILURE);
  244.     }
  245. #if CAN_RESIZE
  246.     if (nonposix_resize)
  247.     (void) signal(SIGWINCH, adjust);    /* arrange interrupts to resize */
  248. #endif
  249.  
  250.     /* slurp the file */
  251.     for (lptr = &my_lines[0]; (lptr - my_lines) < MAXLINES; lptr++) {
  252.     char temp[BUFSIZ], *s, *d;
  253.     int col;
  254.  
  255.     if (fgets(buf, sizeof(buf), fp) == 0)
  256.         break;
  257.  
  258.     /* convert tabs so that shift will work properly */
  259.     for (s = buf, d = temp, col = 0; (*d = *s) != '\0'; s++) {
  260.         if (*d == '\n') {
  261.         *d = '\0';
  262.         break;
  263.         } else if (*d == '\t') {
  264.         col = (col | 7) + 1;
  265.         while ((d - temp) != col)
  266.             *d++ = ' ';
  267.         } else
  268. #if USE_WIDEC_SUPPORT
  269.         col++, d++;
  270. #else
  271.         if (isprint(UChar(*d))) {
  272.         col++;
  273.         d++;
  274.         } else {
  275.         sprintf(d, "\\%03o", UChar(*s));
  276.         d += strlen(d);
  277.         col = (d - temp);
  278.         }
  279. #endif
  280.     }
  281.     *lptr = ch_dup(temp);
  282.     }
  283.     (void) fclose(fp);
  284.     length = lptr - my_lines;
  285.  
  286.     (void) initscr();        /* initialize the curses library */
  287.     keypad(stdscr, TRUE);    /* enable keyboard mapping */
  288.     (void) nonl();        /* tell curses not to do NL->CR/NL on output */
  289.     (void) cbreak();        /* take input chars one at a time, no wait for \n */
  290.     (void) noecho();        /* don't echo input */
  291.     nodelay(stdscr, TRUE);
  292.     idlok(stdscr, TRUE);    /* allow use of insert/delete line */
  293.  
  294.     if (try_color) {
  295.     if (has_colors()) {
  296.         start_color();
  297.         init_pair(my_pair, COLOR_WHITE, COLOR_BLUE);
  298.         bkgd(COLOR_PAIR(my_pair));
  299.     } else {
  300.         try_color = FALSE;
  301.     }
  302.     }
  303.  
  304.     lptr = my_lines;
  305.     while (!done) {
  306.     int n, c;
  307.  
  308.     if (!got_number)
  309.         show_all(my_label);
  310.  
  311.     n = 0;
  312.     for (;;) {
  313. #if CAN_RESIZE
  314.         if (interrupted) {
  315.         adjust(0);
  316.         my_label = "interrupt";
  317.         }
  318. #endif
  319.         waiting = TRUE;
  320.         c = getch();
  321.         waiting = FALSE;
  322.         if ((c < 127) && isdigit(c)) {
  323.         if (!got_number) {
  324.             mvprintw(0, 0, "Count: ");
  325.             clrtoeol();
  326.         }
  327.         addch(c);
  328.         value = 10 * value + (c - '0');
  329.         got_number = TRUE;
  330.         } else
  331.         break;
  332.     }
  333.     if (got_number && value) {
  334.         n = value;
  335.     } else {
  336.         n = 1;
  337.     }
  338.  
  339.     if (c != ERR)
  340.         my_label = keyname(c);
  341.     switch (c) {
  342.     case KEY_DOWN:
  343.     case 'n':
  344.         olptr = lptr;
  345.         for (i = 0; i < n; i++)
  346.         if ((lptr - my_lines) < (length - LINES + 1))
  347.             lptr++;
  348.         else
  349.             break;
  350.         wscrl(stdscr, lptr - olptr);
  351.         break;
  352.  
  353.     case KEY_UP:
  354.     case 'p':
  355.         olptr = lptr;
  356.         for (i = 0; i < n; i++)
  357.         if (lptr > my_lines)
  358.             lptr--;
  359.         else
  360.             break;
  361.         wscrl(stdscr, lptr - olptr);
  362.         break;
  363.  
  364.     case 'h':
  365.     case KEY_HOME:
  366.         lptr = my_lines;
  367.         break;
  368.  
  369.     case 'e':
  370.     case KEY_END:
  371.         if (length > LINES)
  372.         lptr = my_lines + length - LINES + 1;
  373.         else
  374.         lptr = my_lines;
  375.         break;
  376.  
  377.     case 'r':
  378.     case KEY_RIGHT:
  379.         shift += n;
  380.         break;
  381.  
  382.     case 'l':
  383.     case KEY_LEFT:
  384.         shift -= n;
  385.         if (shift < 0) {
  386.         shift = 0;
  387.         beep();
  388.         }
  389.         break;
  390.  
  391.     case 'q':
  392.         done = TRUE;
  393.         break;
  394.  
  395. #ifdef KEY_RESIZE
  396.     case KEY_RESIZE:    /* ignore this; ncurses will repaint */
  397.         break;
  398. #endif
  399.     case 's':
  400.         if (got_number) {
  401.         halfdelay(my_delay = n);
  402.         } else {
  403.         nodelay(stdscr, FALSE);
  404.         my_delay = -1;
  405.         }
  406.         break;
  407.     case ' ':
  408.         nodelay(stdscr, TRUE);
  409.         my_delay = 0;
  410.         break;
  411.     case ERR:
  412.         if (!my_delay)
  413.         napms(50);
  414.         break;
  415.     default:
  416.         beep();
  417.         break;
  418.     }
  419.     if (c >= KEY_MIN || (c > 0 && !isdigit(c))) {
  420.         got_number = FALSE;
  421.         value = 0;
  422.     }
  423.     }
  424.  
  425.     finish(0);            /* we're done */
  426. }
  427.  
  428. static RETSIGTYPE
  429. finish(int sig)
  430. {
  431.     endwin();
  432.     ExitProgram(sig != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
  433. }
  434.  
  435. #if CAN_RESIZE
  436. /*
  437.  * This uses functions that are "unsafe", but it seems to work on SunOS and
  438.  * Linux.  Usually:  the "unsafe" refers to the functions that POSIX lists
  439.  * which may be called from a signal handler.  Those do not include buffered
  440.  * I/O, which is used for instance in wrefresh().  To be really portable, you
  441.  * should use the KEY_RESIZE return (which relies on ncurses' sigwinch
  442.  * handler).
  443.  *
  444.  * The 'wrefresh(curscr)' is needed to force the refresh to start from the top
  445.  * of the screen -- some xterms mangle the bitmap while resizing.
  446.  */
  447. static RETSIGTYPE
  448. adjust(int sig)
  449. {
  450.     if (waiting || sig == 0) {
  451.     struct winsize size;
  452.  
  453.     if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) {
  454.         resize_term(size.ws_row, size.ws_col);
  455.         wrefresh(curscr);    /* Linux needs this */
  456.         show_all(sig ? "SIGWINCH" : "interrupt");
  457.     }
  458.     interrupted = FALSE;
  459.     } else {
  460.     interrupted = TRUE;
  461.     }
  462.     (void) signal(SIGWINCH, adjust);    /* some systems need this */
  463. }
  464. #endif /* CAN_RESIZE */
  465.  
  466. static void
  467. show_all(const char *tag)
  468. {
  469.     int i;
  470.     char temp[BUFSIZ];
  471.     NCURSES_CH_T *s;
  472.     time_t this_time;
  473.  
  474. #if CAN_RESIZE
  475.     sprintf(temp, "%s (%3dx%3d) col %d ", tag, LINES, COLS, shift);
  476.     i = strlen(temp);
  477.     sprintf(temp + i, "view %.*s", (int) (sizeof(temp) - 7 - i), fname);
  478. #else
  479.     sprintf(temp, "view %.*s", (int) sizeof(temp) - 7, fname);
  480. #endif
  481.     move(0, 0);
  482.     printw("%.*s", COLS, temp);
  483.     clrtoeol();
  484.     this_time = time((time_t *) 0);
  485.     strcpy(temp, ctime(&this_time));
  486.     if ((i = strlen(temp)) != 0) {
  487.     temp[--i] = 0;
  488.     if (move(0, COLS - i - 2) != ERR)
  489.         printw("  %s", temp);
  490.     }
  491.  
  492.     scrollok(stdscr, FALSE);    /* prevent screen from moving */
  493.     for (i = 1; i < LINES; i++) {
  494.     move(i, 0);
  495.     printw("%3ld:", (long) (lptr + i - my_lines));
  496.     clrtoeol();
  497.     if ((s = lptr[i - 1]) != 0) {
  498.         int len = ch_len(s);
  499.         if (len > shift)
  500. #if USE_WIDEC_SUPPORT
  501.         add_wchstr(s + shift);
  502. #else
  503.         addchstr(s + shift);
  504. #endif
  505.         if (try_color)
  506.         wchgat(stdscr, -1, A_NORMAL, my_pair, NULL);
  507.     }
  508.     }
  509.     setscrreg(1, LINES - 1);
  510.     scrollok(stdscr, TRUE);
  511.     refresh();
  512. }
  513.